unit IIONamedDeviceThread;

interface
uses
  {$IFNDEF FPC}
  Windows,
  {$ENDIF}
  SysUtils,
  IPollThread,
  IOPort,
  idata,
  INamedDevice;

type
  EOIONamedDeviceThread = class(EOIPollThread)
  private
    FBuildingXml: Boolean;
    FXMLString: String;
    FBuffer: EOIOBuffer;

  protected
    procedure on_xml(Value: String); virtual;
    procedure on_string(Value: String); virtual;
    procedure on_char(Value: Char); virtual;

    procedure DoAssemble; override;

    //function WriteToPort(Data: EOIOBuffer): Boolean; override;

    function Active: Boolean; override;
    procedure RemoveThread; override;

  public
    constructor Create(AOwner: EOINamedDevice; IOPort: EOIOPort);
    destructor Destroy; override;

  end;

const
  EOTextHeader = '<xml';
  EOTextFooter = '/xml>';

implementation

procedure EOIONamedDeviceThread.on_xml(Value: String);
begin
  if Assigned(EOINamedDevice(Owner).OnXMLEvent) then begin
    FBuffer.Flush;
    FBuffer.Push(Value);
    EOINamedDevice(Owner).OnXMLEvent(FBuffer);
    if FBuffer.Count > 0 then begin
      if LockOutData(1000) then begin
        try
          OutData.Push(FBuffer);
        finally
          UnlockOutData;
        end;
      end;
    end;
  end;
end;

procedure EOIONamedDeviceThread.on_string(Value: String);
begin
  if Assigned(EOINamedDevice(Owner).OnStringEvent) then begin
    FBuffer.Flush;
    FBuffer.Push(Value);
    EOINamedDevice(Owner).OnStringEvent(OutData);
    if FBuffer.Count > 0 then begin
      if LockOutData(1000) then begin
        try
          OutData.Push(FBuffer);
        finally
          UnlockOutData;
        end;
      end;
    end;
  end;
end;

procedure EOIONamedDeviceThread.on_char(Value: Char);
begin
  if Assigned(EOINamedDevice(Owner).OnCharEvent) then begin
    FBuffer.Flush;
    FBuffer.Push(Value);
    EOINamedDevice(Owner).OnCharEvent(OutData);
    if FBuffer.Count > 0 then begin
      if LockOutData(1000) then begin
        try
          OutData.Push(FBuffer);
        finally
          UnlockOutData;
        end;
      end;
    end;
  end;
end;

procedure EOIONamedDeviceThread.DoAssemble;
var
  tmpS, strMsg: String;
  i: Integer;
begin
  if RawData.Count > 0 then
    RawData.Pop(tmpS);

  while Length(tmpS) > 0 do begin
    if FBuildingXml then begin
      // continue append this string until closing tag is reached '/xml>'
      i := Pos(EOTextFooter, tmpS);
      if i > 0 then begin
        FXMLString := FXMLString + Copy(tmpS, 1, i + Length(EOTextFooter) - 1);
        Delete(tmpS, 1, i + Length(EOTextFooter) - 1);
        FBuildingXml := False;

        on_xml(FXMLString);
        Break;
      end
      else begin
        FXMLString := FXMLString + tmpS;
        tmpS := '';
      end;
    end
    else begin
      // scan for openning tag '<xml '
      i := Pos(EOTextHeader, tmpS);
      if i > 0  then begin
        FXMLString := '';
        FBuildingXml := True;

        if i > 1 then begin
          FBuildingXml := False;
          strMsg := Copy(tmpS, 1, i-1);
          Delete(tmpS, 1, i-1);
          on_string(strMsg);
          Break;
        end;
      end
      else begin
        on_string(tmpS);
        tmpS := '';
        Break;
      end;
    end;
  end;

  if Length(tmpS) > 0 then begin
    if not RawData.Push(tmpS) then
      Reset;
  end;
end;

//function EOIONamedDeviceThread.WriteToPort(Data: EOIOBuffer): Boolean;
////var
////  tmpI: Integer;
//begin
//  Data.Push(OutData);
//  OutData.Flush;
//
//  Result := Inherited WriteToPort(Data);
//
//{  if EOINamedDevice(Owner).Active then begin
//    tmpI := InterlockedIncrement(EOINamedDevice(Owner).FDataOutLock);
//    try
//      if tmpI = 1 then begin
//        Data.Flush;
//        Data.Push(EOINamedDevice(Owner).DataOut);
//        EOINamedDevice(Owner).DataOut.Flush;
//      end;
//    finally
//      InterlockedDecrement(EOINamedDevice(Owner).FDataOutLock);
//    end;
//
//    Result := Inherited WriteToPort(Data);
//  end
//  else
//    Result := False;
//}
//end;

function EOIONamedDeviceThread.Active: Boolean;
begin
  Result := EOINamedDevice(Owner).Active;
end;

procedure EOIONamedDeviceThread.RemoveThread;
begin
  EOINamedDevice(Owner).RemoveThread(Self);
end;

constructor EOIONamedDeviceThread.Create(AOwner: EOINamedDevice; IOPort: EOIOPort);
begin
  Inherited Create(AOwner, IOPort);

  FBuffer := EOIOBuffer.Create;
end;

destructor EOIONamedDeviceThread.Destroy;
begin
  FBuffer.Free;

  Inherited;
end;

end.

